
#include "StringHasher.h"
#include <assert.h>

using namespace tagfolder;

unsigned long SDBHash::operator() ( const char* str){
    unsigned long hash = 0;

    while (*str) {
        // equivalent to: hash = 65599*hash + (*str++);
        hash = (*str++) + (hash << 6) + (hash << 16) - hash;
    }

    return (hash & 0x7FFFFFFF);
}

unsigned long RSHash::operator() ( const char* str){
    unsigned long b = 378551;
    unsigned long a = 63689;
    unsigned long hash = 0;

    while (*str) {
        hash = hash * a + (*str++);
        a *= b;
    }

    return (hash & 0x7FFFFFFF);
}


unsigned long JSHash::operator() ( const char* str){
    unsigned int hash = 1315423911;

    while (*str) {
        hash ^= ((hash << 5) + (*str++) + (hash >> 2));
    }

    return (hash & 0x7FFFFFFF);
}


unsigned long PJWHash::operator() ( const char* str){
    static unsigned long BitsInUnignedInt = (unsigned long)(sizeof(unsigned long) * 8);
    static unsigned long ThreeQuarters	= (unsigned long)((BitsInUnignedInt  * 3) / 4);
    static unsigned long OneEighth = (unsigned long)(BitsInUnignedInt / 8);
    static unsigned long HighBits = (unsigned long)(0xFFFFFFFF) << (BitsInUnignedInt - OneEighth);
    unsigned long hash = 0;
    unsigned long test = 0;

    while (*str) {
        hash = (hash << OneEighth) + (*str++);
        if ((test = hash & HighBits) != 0) {
            hash = ((hash ^ (test >> ThreeQuarters)) & (~HighBits));
        }
    }

    return (hash & 0x7FFFFFFF);
}

unsigned long ELFHash:: operator() ( const char* str){
    unsigned long hash = 0;
    unsigned long x	= 0;

    while (*str) {
        hash = (hash << 4) + (*str++);
        if ((x = hash & 0xF0000000L) != 0) {
            hash ^= (x >> 24);
            hash &= ~x;
        }
    }

    return (hash & 0x7FFFFFFF);
}

unsigned long APHash::operator() ( const char * str){
    unsigned long hash = 0;
    int i;

    for (i=0; *str; i++) {
        if ((i & 1) == 0) {
            hash ^= ((hash << 7) ^ (*str++) ^ (hash >> 3));
        } else {
            hash ^= (~((hash << 11) ^ (*str++) ^ (hash >> 5)));
        }
    }

    return (hash & 0x7FFFFFFF);
}

/////////////////////////////StringHasher Implementation//////////////////////////////////

StringHasher* tagfolder::StringHasher::m_instance=NULL;

StringHasher::StringHasher(){
    m_algCount=3;
    m_alg=new StrHashAlgPtr[m_algCount];

    m_alg[0]=new JSHash();
    m_alg[1]=new APHash();
    m_alg[2]=new RSHash();
}

StringHasher::~StringHasher(){
    if(m_alg!=NULL){
        for( int i=0; i<m_algCount; ++i){
            if( m_alg[i]!=NULL){
                delete m_alg[i];
            }
        }
        delete[] m_alg;
    }
}

// The central idea of this hash function is too make use of multiple 
// elementary hash algorithms to XOR a more indentical hashCode;
unsigned long StringHasher::makeHash( const char* str){
    unsigned long hash=0;

    assert( m_alg!=NULL && m_algCount>=1);
    if( str!=NULL){
        hash=(*(m_alg[0]))( str);
        for( int i=1; i< m_algCount; ++i){
            StrHashAlg& ref=*(m_alg[i]);
            hash^=(ref(str)); 
        }
        return hash;
    }
    return hash;
}
